package com.asdhawaii.otello.board;

import com.asdhawaii.otello.util.ImageLoader;
import java.awt.Color;
import javax.swing.JButton;

/**
 * An individual square on the Othello board.
 * A square may be empty or have a piece on it; this piece may be black or white.
 * The background of the square should be #00A651, which is supposedly "pure green"
 * despite having only about two-thirds green compared to one-third blue.
 * 
 * Note that certain squares have special names:
 * 
 *  |0|1|2|3|4|5|6|7|
 *  .-.-.-.-.-.-.-.-.
 * 0|!|C|A| | |A|C|!|
 * -.-.-.-.-.-.-.-.-.
 * 1|C|X| | | | |X|C|
 * -.-.-.-.-.-.-.-.-.
 * 2|A| | | | | | |A|
 * -.-.-.-.-.-.-.-.-. !: Corner
 * 3| | | | | | | | | C: Next to corner
 * -.-.-.-.-.-.-.-.-. X: Next to corner on diagonal 
 * 4| | | | | | | | | A: Two away from corner; 
 * -.-.-.-.-.-.-.-.-. 
 * 5|A| | | | | | |A|
 * -.-.-.-.-.-.-.-.-.
 * 6|C|X| | | | |X|C|
 * -.-.-.-.-.-.-.-.-.
 * 7|!|C|A| | |A|C|!|
 * -.-.-.-.-.-.-.-.-.
 * 
 * @author Branden Ogata
 *
 */

@SuppressWarnings("serial")
public class Square extends JButton
{  
  /**
   * The current contents of this Square.
   * 
   */
  private SquareContents contents;

  /**
   * Indicates if the piece on the Square is currently flipping.
   * 
   */
  private boolean flipping;
  
  /**
   * The name of the current image on this Square.
   * 
   */
  private String imageName;
  
  /**
   * Creates a new, empty Square.
   * 
   */
  
  public Square()
  {
    this(SquareContents.EMPTY);
  }
  
  /**
   * Creates a new Square with the contents given in the parameter.
   * 
   * @param contents The SquareContents indicating what to place in the Square.
   * 
   */
  
  public Square(SquareContents contents)
  {
    super();
    this.contents = contents;
    this.flipping = false;
    this.setBackground(new Color(0, 166, 81));
    this.setFocusPainted(false);
    this.setRolloverEnabled(false);
    this.setRequestFocusEnabled(false);
    
    // Set the appropriate icon
    switch (this.contents)
    {
      case WHITE:
        this.imageName = "white-black_s_00.jpg";
        break;
      case BLACK:
        this.imageName = "black-white_s_00.jpg";
        break;
      case EMPTY:
      default:
        this.imageName = "empty_s.jpg";
        break;
    }
    
    this.setIcon(ImageLoader.getImageIcon(this, this.imageName));
  }

  /**
   * Returns the contents of this Square.
   *
   * @return contents The SquareContents containing the contents of this Square.
   *
   */
  
  public SquareContents getContents()
  {
    return this.contents;
  }

  /**
   * Sets the contents of this Square, changing the icon to match.
   *
   * @param contents The SquareContents containing the contents to set.
   *
   */
  
  public void setContents(SquareContents contents)
  {
    // If the square is being set to empty (as may be the case when resetting the board)
    if (contents.equals(SquareContents.EMPTY))
    {
      this.contents = contents;
      this.imageName = "empty_s.jpg";
      this.setIcon(ImageLoader.getImageIcon(this, imageName));
      /*
      System.out.println("Setting " + this.getName() + " to empty");
      */
    }
    // If the square is currently empty
    else if (this.contents.equals(SquareContents.EMPTY))
    {
      // Assign the current contents and change the icon to the correct piece
      this.contents = contents;      
      this.imageName = ((this.contents.toString().equals("B")) ? 
                        ("black") : ("white")) + "-" + 
                        ((this.contents.toString().equals("B")) ? 
                        ("white") : ("black")) + "_s_00.jpg";
      this.setIcon(ImageLoader.getImageIcon(this, this.imageName));
      /*
      System.out.println("Placing " + contents + " at " + this.getName());
      */
    }
    // If the square is being set to its current value
    else if (this.contents.equals(contents))
    {
      this.setIcon(ImageLoader.getImageIcon(this, this.imageName));
      /*
      System.out.println("Refreshing " + this.getName() + " to " + contents);
      */
    }
    // Else this must be a flipping motion
    else
    {
      /*
      System.out.println("Flipping " + this.getName() + ": " + this.contents + " to " + contents);
      new FlipTask(this.contents).execute();
      this.contents = this.contents.opposite();
      */
      this.setFlipping(true);
      this.contents = this.contents.opposite();
    }
    
    this.repaint();
  }  
  
  /**
   * Indicates if this Square is currently showing an animation.
   * 
   * @return flipping A boolean that is true if there is a flipping animation on this Square,
   *                                    false otherwise.
   *                                    
   */
  
  public boolean isFlipping()
  {
    return this.flipping;
  }
  
  /**
   * Marks this Square to indicate that it is currently showing an animation.
   * 
   * @param flipping A boolean that is true if this Square should show an animation,
   *                                   false otherwise.
   *                                   
   */
  
  public void setFlipping(boolean flipping)
  {
    this.flipping = flipping;
  }
    
  /**
   * Returns the name of the image in this Square.
   *
   * @return imageName The String containing the name of the image in this Square.
   *
   */
  
  public String getImageName()
  {
    return this.imageName;
  }

  /**
   * Sets the name of the image in this Square.
   *
   * @param imageName The String containing the name to set for the image.
   *
   */
  
  public void setImageName(String imageName)
  {
    this.imageName = imageName;
  }

  /**
   * Indicates if this Square is a corner square.
   * 
   * @return A boolean that is true if this Square is a corner,
   *                           false otherwise.
   *                           
   */
  
  public boolean isCorner()
  {
    return (this.getName().equals("00")) || (this.getName().equals("07")) || 
           (this.getName().equals("70")) || (this.getName().equals("77"));
  }
  
  /**
   * Indicates if this Square is an A square.
   * 
   * @return A boolean that is true if this Square is against an edge and two spaces from a corner,
   *                           false otherwise.
   *                           
   */
  
  public boolean isASquare()
  {
    return ((this.getName().contains("0")) || (this.getName().contains("7"))) && 
           ((this.getName().contains("2")) || (this.getName().contains("5")));
  }
  
  /**
   * Indicates if this Square is a C square.
   * 
   * @return A boolean that is true if this Square is orthagonally adjacent to a corner,
   *                           false otherwise.
   *                            
   */
  
  public boolean isCSquare()
  {
    return ((this.getName().contains("0")) || (this.getName().contains("7"))) && 
           ((this.getName().contains("1")) || (this.getName().contains("6")));
  }
  
  /**
   * Indicates if this Square is an X square.
   * 
   * @return A boolean that is true if this Square is diagonally adjacent to a corner,
   *                           false otherwise.
   * 
   */
  
  public boolean isXSquare()
  {
    return (this.getName().equals("11")) || (this.getName().equals("16")) || 
           (this.getName().equals("61")) || (this.getName().equals("66"));
  }
  
  /**
   * Compares this Square to an object to test for equality.
   * 
   * @param obj The Object to compare this Square to.
   * 
   * @return isEqual A boolean that is true if this Square is equal to the parameter,
   *                                   false otherwise.
   *                                   
   */
  
  @Override
  public boolean equals(Object obj)
  {
    boolean isEqual = false;
    
    if (this == obj)
    {
      isEqual = true;
    }
    else if (obj instanceof Square)
    {
      Square temp = (Square) obj;
      
      // The instances are equal if their contents are the same
      if (this.contents.equals(temp.contents))
      {
        isEqual = true;
      }
    }
    
    return isEqual;
  }
  
  /**
   * Returns a hash code based on this Square object.
   * Based on the suggestions in Effective Java, Chapter 3.
   * 
   * @return result An int equal to the hash code for this Square instance.
   * 
   */
  
  @Override
  public int hashCode()
  {
    int result = 17;
    int combination = this.contents.hashCode();
    result = 11 * result + combination;
    return result;
  }
  
  /**
   * Returns a String representation of this Square object.
   * 
   * @return "B" if this.contents is SquareContents.BLACK
   *         "W" if this.contents is SquareContents.WHITE
   *         " " if this.contents is SquareContents.EMPTY
   *         
   */
  
  @Override
  public String toString()
  {
    return this.contents.toString();
  }
}